// Copyright (C) ZHENG Zhong <heavyzheng nospam-at gmail D0T com>
//
// $Id: node_set.hpp 317 2009-01-12 11:10:14Z heavyzheng $
//

#ifndef ZZHENG_XML_DOM_NODE_SET_HPP_20080726__
#define ZZHENG_XML_DOM_NODE_SET_HPP_20080726__

#include <zzheng/xml/config.hpp>
#include <zzheng/xml/dom/types.hpp>

#include <zzheng/xml/dom/libxml2/node.hpp>
#include <zzheng/xml/dom/libxml2/libxml2_fwd.hpp>

namespace zzheng {
namespace xml {
namespace dom {
namespace libxml2_ {

    class xpath_result;
    class node_set;

    ////////////////////////////////////////////////////////////////////////////////////////////////
    // basic_node_set_iterator
    //

    //! This class template represents an iterator to an XML node contained in a node set.
    template<class T>
    class basic_node_set_iterator {

        friend class node_set;

    private:

        typedef basic_node_set_iterator<T> this_type;

    public:

        typedef T   value_type;
        typedef T&  reference;
        typedef T*  pointer;

    public:

        explicit basic_node_set_iterator(): nodes_(0), index_(0) {
            // Do nothing.
        }

        // Use auto-generated copy constructor.
        // Use auto-generated copy assignment.
        // Use auto-generated destructor.

        bool operator==(const this_type& rhs) const {
            if (is_end() && rhs.is_end()) {
                return true;
            } else {
                return ( nodes_ == rhs.nodes_ && index_ == rhs.index_ );
            }
        }

        bool operator!=(const this_type& rhs) const {
            return !operator==(rhs);
        }

        reference operator*() const {
            return (*current());
        }

        pointer operator->() const {
            return current();
        }

        this_type& operator++() {
            increment();
            return *this;
        }

        this_type operator++(int) {
            this_type tmp(*this);
            increment();
            return tmp;
        }

        this_type& operator--() {
            decrement();
            return *this;
        }

        this_type operator--(int) {
            this_type tmp(*this);
            decrement();
            return tmp;
        }

        basic_node_ptr<value_type> ptr() const {
            return basic_node_ptr<value_type>(current());
        }

    private:

        explicit basic_node_set_iterator(xmlNodeSet* nodes, int index)
        : nodes_(nodes), index_(index) {
            // Do nothing.
        }

        void increment() {
            ++index_;
        }

        void decrement() {
            --index_;
        }

        bool is_end() const {
            return (nodes_ == 0 || index_ >= nodes_->nodeNr);
        }

        pointer current() const {
            if (nodes_ != 0 && index_ >= 0 && index_ < nodes_->nodeNr) {
                return static_cast<pointer>( nodes_->nodeTab[index_]->_private );
            } else {
                return 0;
            }
        }

    private:

        xmlNodeSet* nodes_; //!< Raw pointer to the xmlNodeSet object.
        int         index_; //!< The current node index of this iterator.

    }; // class basic_node_set_iterator<T>

    ////////////////////////////////////////////////////////////////////////////////////////////////
    // node_set
    //

    //! This class represents a node set evaluated from an XPath expression. It is a wrapper around
    //! an xmlNodeSet object. It does not create or destroy the underlying object, because the
    //! object belongs to an xmlXPathObject, which is managed by an xpath_result object. When the
    //! owner xmlXPathObject is destroyed, the xmlNodeSet object will also be freed.
    class node_set {

        friend class xpath_result; // Friend class declaration.

    public:

        typedef basic_node_set_iterator<node>        iterator;       //!< Iterator type.
        typedef basic_node_set_iterator<const node>  const_iterator; //!< Const iterator type.

    public:

        //! Default constructor. Constructs an empty node set.
        explicit node_set();

        // Use auto-generated copy constructor.
        // Use auto-generated copy assignment.
        // Use auto-generated destructor.

        //! Checks if this node set is empty.
        //! \return true if this node set is empty, false otherwise.
        bool empty() const;

        //! Returns the size of this node set.
        //! \return the size of this node set.
        size_type size() const;

        //! Returns an iterator to the first node of this node set.
        //! \return an iterator to the first node of this node set.
        iterator begin();

        //! Returns an iterator just past the last node of this node set.
        //! \return an iterator just past the last node of this node set.
        iterator end();

        //! Const version of begin().
        const_iterator begin() const;

        //! Const version of end().
        const_iterator end() const;

    private:

        //! Private constructor to construct a node set from an underlying xmlNodeSet object.
        //! \param px  the underlying xmlNodeSet object, may be null.
        explicit node_set(xmlNodeSet* px);

    private:

        xmlNodeSet* raw_; //!< Raw pointer to libxml2 node set object.

    }; // class node_set

} // namespace zzheng::xml::dom::libxml2_
} // namespace zzheng::xml::dom
} // namespace zzheng::xml
} // namespace zzheng

#endif // ZZHENG_XML_DOM_NODE_SET_HPP_20080726__



